#include <sys_config.h>
#include <basic_types.h>
#include <retcode.h>
#include <types.h>
#include <api/libc/printf.h>
#include <osal/osal.h>
#include <api/libc/string.h>
#include <api/libtsi/db_3l.h>
#include <api/libtsi/sie.h>
#include <api/libsi/si_module.h>
#include "ews_indonesia.h"
#include "copper_common/com_api.h"
#include "copper_common/system_data.h"

#ifdef EWS_INDONESIA_DEMO

#define EWS_PR(...)
//libc_printf

#define EWS_INDONESIA_PID 0x80
#define TABLE_ID_TRDW     0x01
#define TABLE_ID_TCDW     0x02
#define TABLE_ID_TMDW     0x03


static UINT8 g_ews_section_buff[PSI_SHORT_SECTION_LENGTH];
static struct si_filter_t *g_ews_filter = NULL;
static BOOL g_ews_indonesia_show_flag = FALSE;
static BOOL g_ews_indonesia_started = FALSE;
static ews_indonesia_t *g_ews_indonesia_event = NULL;
static UINT8 g_event_flag = 0;

static UINT32 ap_ews_indonesia_get_sys_location_code(void)
{
// get from system_data.location_code
    return sys_data_get_location_code();
    //return 34567;
}

static void dump_ews_event(void)
{
    if (g_ews_indonesia_event)
    {
        libc_printf("\n\nlocation_code %d\n", g_ews_indonesia_event->location_code);
        libc_printf("disaster_code %d\n", g_ews_indonesia_event->disaster_code);
        libc_printf("package_id %d\n", g_ews_indonesia_event->package_id);
        libc_printf("authority %d\n", g_ews_indonesia_event->authority);
        libc_printf("warning_level %d\n", g_ews_indonesia_event->warning_level);
        if (g_ews_indonesia_event->location_desc)
        {
            libc_printf("location_desc: %s\n", g_ews_indonesia_event->location_desc);
        }
        if (g_ews_indonesia_event->disaster_desc)
        {
            libc_printf("disaster_desc: %s\n", g_ews_indonesia_event->disaster_desc);
        }
        if (g_ews_indonesia_event->disaster_position)
        {
            libc_printf("disaster_position: %s\n", g_ews_indonesia_event->disaster_position);
        }
        if (g_ews_indonesia_event->disaster_date)
        {
            libc_printf("disaster_date: %s\n", g_ews_indonesia_event->disaster_date);
        }
        if (g_ews_indonesia_event->disaster_characteristic)
        {
            libc_printf("disaster_characteristic: %s\n", g_ews_indonesia_event->disaster_characteristic);
        }
        if (g_ews_indonesia_event->message_content)
        {
            libc_printf("message_content: %s\n", g_ews_indonesia_event->message_content);
        }
    }

}
static void ap_ews_indonesia_check_event(void)
{
    if (g_ews_indonesia_event != NULL && g_event_flag == 0x0E) // 1110
    {
        if (g_ews_indonesia_show_flag)
        {
            dump_ews_event();
            // SEND MSG to ap_control_task
            ap_send_msg(CTRL_MSG_SUBTYPE_CMD_EWS_INDONESIA_EVENT, 0, 0);
            g_ews_indonesia_show_flag = FALSE; // only send once
        }
    }
}

static void ap_ews_indonesia_event_release(void)
{
    if (g_ews_indonesia_event != NULL)
    {
        if (g_ews_indonesia_event->location_desc)
        {
            FREE(g_ews_indonesia_event->location_desc);
        }
        if (g_ews_indonesia_event->disaster_desc)
        {
            FREE(g_ews_indonesia_event->disaster_desc);
        }
        if (g_ews_indonesia_event->disaster_position)
        {
            FREE(g_ews_indonesia_event->disaster_position);
        }
        if (g_ews_indonesia_event->disaster_date)
        {
            FREE(g_ews_indonesia_event->disaster_date);
        }
        if (g_ews_indonesia_event->disaster_characteristic)
        {
            FREE(g_ews_indonesia_event->disaster_characteristic);
        }
        if (g_ews_indonesia_event->message_content)
        {
            FREE(g_ews_indonesia_event->message_content);
        }
        FREE(g_ews_indonesia_event);
    }

    g_ews_indonesia_event = NULL;
}

static BOOL ap_ews_indonesia_event_new(void)
{
    if (g_ews_indonesia_event != NULL)
    {
        ap_ews_indonesia_event_release();
    }
    g_ews_indonesia_event = (ews_indonesia_t *)MALLOC(sizeof(ews_indonesia_t));

    if (g_ews_indonesia_event == NULL)
    {
        return FALSE;
    }
    MEMSET(g_ews_indonesia_event, 0, sizeof(ews_indonesia_t));

    return TRUE;
}

static void ap_ews_indonesia_trdw(UINT8 *buff, INT32 length)
{
    UINT8 package_id  = 0;
    UINT16 disaster_code = 0;
    UINT8 warning_level = 0;
    UINT32 location_code = 0;
    UINT8 location_code_description[256] = {0};
    UINT8 location_code_desc_len = 0;
    UINT32 sys_location_code = 0;
    UINT8 *p = NULL;
    UINT8 *loop_end = NULL;
    UINT8  tmp = 0;
    INT32 i = 0;
    
    disaster_code = (buff[8]<<8)|buff[9];
    warning_level = buff[10];
    package_id    = buff[11];
    p = &buff[13];
    loop_end = buff + length -4; // reduce CRC32

    EWS_PR("\n\nTRDW-------------------------------------\n");
    sys_location_code = ap_ews_indonesia_get_sys_location_code();
    while (p<loop_end)
    {
        tmp = 0;
        tmp = *p;
        location_code = ((tmp>>4)*10) + (tmp&0x0F);
        p++;
        
        tmp = 0;
        tmp = *p;
        location_code = (location_code*100) + ((tmp>>4)*10) + (tmp&0x0F);
        p++;
        
        tmp = 0;
        tmp = *p;
        location_code = (location_code*10) + (tmp>>4);
        p++;

        location_code_desc_len = *p;
        p++;
        if (location_code == sys_location_code)
        {
            for (i=0; i<location_code_desc_len; i++)
            {
                location_code_description[i] = *p;
                p++;
            }
            if ((NULL == g_ews_indonesia_event) && (TRUE == ap_ews_indonesia_event_new()))
            {
                g_ews_indonesia_event->package_id = package_id;
                g_ews_indonesia_event->disaster_code = disaster_code;
                g_ews_indonesia_event->warning_level = warning_level;
                g_ews_indonesia_event->location_code = location_code;
                if (g_ews_indonesia_event->location_desc == NULL)
                {
                    g_ews_indonesia_event->location_desc = strdup(location_code_description);
                }

                g_event_flag |= 0x01<<TABLE_ID_TRDW;
            }
            //EWS_PR("  package id: %d\n", package_id);
            //EWS_PR("  disaster code: %d\n", disaster_code);
            //EWS_PR("  warning level: %d\n", warning_level);
            //EWS_PR("  location: %s\n", location_code_description);
        }
        else
        {
            p += location_code_desc_len;
        }
    }

    ap_ews_indonesia_check_event();
}

static void ap_ews_indonesia_tcdw(UINT8 *buff, INT32 length)
{
    UINT8 package_id  = 0;
    UINT8 authority  = 0;
    UINT16 disaster_code = 0;
    UINT8 description[256];
    UINT8 char_len = 0;
    UINT8 *p = NULL;
    UINT8 *loop_end = NULL;
    BOOL  update_flag = FALSE;
    INT32 i = 0;

    loop_end = buff + length - 4;
    p = &buff[9];
    EWS_PR("\n\nTCDW-------------------------------------\n");

    while (p < loop_end)
    {
        package_id = *p; 
        p++;
        authority  = *p; 
        p++;
        disaster_code = (p[0]<<8)|p[1];
        p += 2;

        EWS_PR("package id: %d\n", package_id);
        EWS_PR("authority: %d\n", authority);

        update_flag = FALSE;
        if (NULL != g_ews_indonesia_event)
        {
            // spec no describe, so I don't know this condition is correct or not.
            if (g_ews_indonesia_event->package_id == package_id)
            {
                update_flag = TRUE;
            }
        }

        if (update_flag)
        {
            g_ews_indonesia_event->authority = authority;
        }

        char_len = *p;
        p++;
        MEMSET(description, 0, 256);
        for (i=0; i<char_len; i++)
        {
            description[i] = *p;
            p++;
        }
        EWS_PR("disaster description:%s\n", description);
        if (update_flag && g_ews_indonesia_event->disaster_desc == NULL)
        {
            g_ews_indonesia_event->disaster_desc = strdup(description);
        }
        char_len = *p;
        p++;
        MEMSET(description, 0, 256);
        for (i=0; i<char_len; i++)
        {
            description[i] = *p;
            p++;
        }
        EWS_PR("position:%s\n", description);
        if (update_flag && g_ews_indonesia_event->disaster_position == NULL)
        {
            g_ews_indonesia_event->disaster_position = strdup(description);
        }

        char_len = *p;
        p++;
        MEMSET(description, 0, 256);
        for (i=0; i<char_len; i++)
        {
            description[i] = *p;
            p++;
        }
        EWS_PR("disaster date:%s\n", description);
        if (update_flag && g_ews_indonesia_event->disaster_date == NULL)
        {
            g_ews_indonesia_event->disaster_date = strdup(description);
        }

        char_len = *p;
        p++;
        MEMSET(description, 0, 256);
        for (i=0; i<char_len; i++)
        {
            description[i] = *p;
            p++;
        }
        EWS_PR("characteristic:%s\n", description);
        if (update_flag && g_ews_indonesia_event->disaster_characteristic == NULL)
        {
            g_ews_indonesia_event->disaster_characteristic = strdup(description);
        }
        if (update_flag)
        {
            g_event_flag |= 0x01<<TABLE_ID_TCDW;
        }

    }

    ap_ews_indonesia_check_event();
    
}

static void ap_ews_indonesia_tmdw(UINT8 *buff, INT32 length)
{
    UINT8 package_id  = 0;
    UINT8 warning_level  = 0;
    UINT16 disaster_code = 0;
    UINT8 description[256];
    UINT16 char_len = 0;
    UINT8 *p = NULL;
    UINT8 *loop_end = NULL;
    INT32 i = 0;
    BOOL update_flag = FALSE;
    
    warning_level = buff[8];
    package_id = buff[9];
    p = &buff[10];
    loop_end = buff + length -4;
    EWS_PR("\n\nTMDW-------------------------------------\n");

    EWS_PR("package id: %d\n", package_id);
    EWS_PR("warning_level: %d\n", warning_level);
    
    if (NULL != g_ews_indonesia_event)
    {
        // spec no describe, so I don't know this condition is correct or not.
        if (g_ews_indonesia_event->package_id == package_id)
        {
            update_flag = TRUE;
        }
    }

    while (p < loop_end)
    {
        char_len = (p[0]<<8)|p[1];
        p += 2;
        MEMSET(description, 0, 256);
        for (i=0; i<char_len; i++)
        {
            description[i] = *p;
            p++;
        }
        EWS_PR("MSG: %s\n", description);
        if (update_flag && g_ews_indonesia_event->message_content == NULL)
        {
            g_ews_indonesia_event->message_content = strdup(description);
        }
        break; // Just get first message, temp solution 
    }

    if (update_flag)
    {
        g_event_flag |= 0x01<<TABLE_ID_TMDW;
    }

    ap_ews_indonesia_check_event();

}

static sie_status_t ap_ews_indonesia_table_cb(UINT16 pid, struct si_filter_t *filter, UINT8 reason, UINT8 *buff, INT32 length)
{
    UINT16 table_id_ext = 0;
    
    if((buff==NULL)||(reason==SIE_REASON_FILTER_TIMEOUT)||(pid != EWS_INDONESIA_PID))
    {
        goto f_exit;
    }

    table_id_ext = (buff[3]<<8)|(buff[4]);

    if (table_id_ext == TABLE_ID_TRDW)
    {
        ap_ews_indonesia_trdw(buff, length);
    }
    else if (table_id_ext == TABLE_ID_TCDW)
    {
        ap_ews_indonesia_tcdw(buff, length);
    }
    else if (table_id_ext == TABLE_ID_TMDW)
    {
        ap_ews_indonesia_tmdw(buff, length);
    }
    
f_exit:
    return sie_started;
}
BOOL ap_ews_indonesia_monitor_start(struct dmx_device *dmx)
{
    struct si_filter_t *filter = NULL;
    struct si_filter_param fparam;
    UINT16 dmx_index = 0;
    UINT8  table_id = 0xB0;
    BOOL   ret = FALSE;
    
    if(dmx == NULL)
    {
        return ret;
    }
    
    dmx_index = get_dmx_index(dmx);
    
    MEMSET(&fparam, 0, sizeof(struct si_filter_param));
    fparam.timeout = OSAL_WAIT_FOREVER_TIME;
    fparam.section_event = NULL;
    fparam.section_parser = (si_handler_t)ap_ews_indonesia_table_cb;

    fparam.mask_value.mask_len = 6;
    fparam.mask_value.value_num = 3;
    fparam.mask_value.tb_flt_msk = 0x07;
    fparam.mask_value.multi_mask[0][0] = 0xFF;
    fparam.mask_value.multi_mask[0][1] = 0xC0;
    fparam.mask_value.multi_mask[0][3] = 0xFF;  // table id ext
    fparam.mask_value.multi_mask[0][4] = 0xFF;  // table id ext
    
    fparam.mask_value.value[0][0] = table_id;
    fparam.mask_value.value[0][1] = 0xC0;
    fparam.mask_value.value[0][3] = 0x0;
    fparam.mask_value.value[0][4] = 0x01;  // TRDW Table Region of Disaster Warning

    fparam.mask_value.multi_mask[0][0] = 0xFF;
    fparam.mask_value.multi_mask[0][1] = 0xC0;
    fparam.mask_value.multi_mask[0][3] = 0xFF;  // table id ext
    fparam.mask_value.multi_mask[0][4] = 0xFF;  // table id ext
    
    fparam.mask_value.value[0][0] = table_id;
    fparam.mask_value.value[0][1] = 0xC0;
    fparam.mask_value.value[0][3] = 0x0;
    fparam.mask_value.value[0][4] = 0x02;  // TCDW Table Code of Disaster Warning

    fparam.mask_value.multi_mask[0][0] = 0xFF;
    fparam.mask_value.multi_mask[0][1] = 0xC0;
    fparam.mask_value.multi_mask[0][3] = 0xFF;  // table id ext
    fparam.mask_value.multi_mask[0][4] = 0xFF;  // table id ext
    
    fparam.mask_value.value[0][0] = table_id;
    fparam.mask_value.value[0][1] = 0xC0;
    fparam.mask_value.value[0][3] = 0x0;
    fparam.mask_value.value[0][4] = 0x03;  // TMDW Table Message of Disaster Warning

    filter = sie_alloc_filter_ext(dmx, EWS_INDONESIA_PID, g_ews_section_buff, 1024,1024,0);

    if (NULL == filter)
    {
        return ret;
    }
    sie_config_filter(filter,&fparam);    

    if (0 != sie_enable_filter(filter))
    {
        return ret;
    }

    g_ews_filter = filter;
    ret = TRUE;

    g_ews_indonesia_started = TRUE;
    return ret;
}

void ap_ews_indonesia_monitor_stop(struct dmx_device *dmx)
{
    sie_abort_filter(g_ews_filter);
    g_ews_indonesia_started = FALSE;
}

BOOL ap_ews_indonesia_check_start(void)
{
    return g_ews_indonesia_started;
}
BOOL ap_ews_indonesia_set_show(BOOL bshow)
{
    g_ews_indonesia_show_flag = bshow;
}

BOOL ap_ews_indonesia_info_reset(void)
{
    ap_ews_indonesia_event_release();
    g_event_flag = 0;
    g_ews_indonesia_show_flag = TRUE;
}

ews_indonesia_t *ap_ews_indonesia_get_event(void)
{
    if (g_ews_indonesia_event == NULL)
    {
        return NULL;
    }

    return g_ews_indonesia_event;
}
#endif


